﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BoYuanCore.Framework;
using FreeSql;
using FreeSqlExtensions;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Serilog;

namespace KeXinApi.Code
{
    public class FreesqlDefault
    {
        /// <summary>
        /// 获取默认aop初始化后的主数据库
        /// </summary>
        public static IFreeSql GetDefaultFreeSql()
        {
            //主要在Startup里new ILogger为serilog太费事了，所以封装了这个重复方法

            var fsql =new FreeSql.FreeSqlBuilder()
            .UseConnectionString(FreeSql.DataType.SqlServer,
                    Appsettings.app(new string[] { "AppSettings", "DbConnection", "ConnectionString" }))
                //.UseGenerateCommandParameterWithLambda(true)//lambda 是否启用参数化
                //.UseNameConvert(NameConvertType.ToLower)//PostgreSQL 要设置为小写 //oracle 要设置为大写
                .UseAutoSyncStructure(false) //自动同步实体结构到数据库
                //.UseMonitorCommand(cmd => Console.WriteLine($"线程：{cmd.CommandText}\r\n"))//监听数据库sql(不想在这里做处理)
                .Build(); //请务必定义成 Singleton 单例模式)

            string DbName = "default";

            fsql.Aop.CommandBefore += (s, args) =>
            {
#if DEBUG
                //输出到控制台显示SQL
                var parInfo = FreeSqlSetup.LookSQL(args.Command.CommandText, args.Command.Parameters);
              
                Log.Information( System.Environment.NewLine
                                       + "-----------------------------------sql-----------------------------------" + System.Environment.NewLine
                                    + "[" + DbName + "] =>>" + parInfo.Item1 + System.Environment.NewLine
                                       + "-----------------------------------sql-----------------------------------" + System.Environment.NewLine
                                    );
#endif
            };

            fsql.Aop.CommandAfter += (s, args) =>
            {
#if DEBUG
                //获取执行后的总毫秒数
                long sqlExecutionTotalMilliseconds = args.ElapsedMilliseconds;
#endif

                if (args.Exception != null)
                {
                    StringBuilder sb_ParameterStr = new StringBuilder("###DbParms参数为:");

                    var parInfo = FreeSqlSetup.LookSQL(args.Command.CommandText, args.Command.Parameters);

                    sb_ParameterStr.Append(parInfo.Item2 != null ? JsonConvert.SerializeObject(parInfo.Item2) : "null");

                    StringBuilder sb_error = new StringBuilder();
                    sb_error.AppendLine("[" + DbName + "]FreeSqlClient执行sql异常信息:" + args.Exception.Message);
                    sb_error.AppendLine("###赋值后sql:" + parInfo.Item1);
                    sb_error.AppendLine("###带参数的sql:" + args.Command.CommandText);
                    sb_error.AppendLine("###参数信息:" + sb_ParameterStr.ToString());
                    sb_error.AppendLine("###StackTrace信息:" + args.Exception.StackTrace);

                    Log.Error(sb_error.ToString());
                }

            };

            if (fsql.Ado.DataType == DataType.Oracle)
            {
                fsql.Aop.AuditDataReader += (obj, ae) =>
                {
                    //处理oracle特有的空字符串存储为null的问题，查询时候string默认null转为空字符串
                    //https://github.com/dotnetcore/FreeSql/issues/436

                    if (ae.DataReader.GetFieldType(ae.Index) == typeof(string) && ae.Value == DBNull.Value)
                        ae.Value = string.Empty;
                };
            }

            fsql.Aop.ConfigEntityProperty += (s, ce) =>
            {
                //默认情况 c# 枚举会映射为 MySql Enum 类型，如果想映射为 int 在 FreeSqlBuilder Build 之后执行以下 Aop 统一处理。https://github.com/dotnetcore/FreeSql/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
                // if (fsql.Ado.DataType == DataType.MySql && ce.Property.PropertyType.IsEnum)
                //     ce.ModifyResult.MapType = typeof(int);

                //为了LookSQL能正常显示Enum特性的值
                if (ce.Property.PropertyType.IsEnum)
                    ce.ModifyResult.MapType = typeof(int);
            };


            return fsql;
        }
    }
}
